from pathlib import Path
from typing import Dict, Any, Optional, Union

import yaml


class ConfigManager:
    """配置管理器，支持点分表示法访问嵌套配置，提供类型安全的方法"""

    # 默认配置文件路径（可根据需要修改）
    default_cfg = Path(__file__).parent.parent / "config" / "config.yaml"

    # 修改 __init__ 方法
    def __init__(self, config_path: Union[str, Path] = default_cfg, config_data: Optional[Dict[str, Any]] = None):
        """
        初始化配置管理器

        Args:
            config_path: 配置文件路径（仅顶层 ConfigManager 使用）
            config_data: 直接传入的配置数据（用于子 ConfigManager）
        """
        if config_data is not None:
            self.config_path = None  # 子管理器无文件路径
            self.config = config_data
        else:
            self.config_path = Path(config_path) if isinstance(config_path, str) else config_path
            # 确保 config_path 不为 None 后再调用 _load_config
            self.config = self._load_config()

    # 修改 _load_config 方法
    def _load_config(self) -> Dict[str, Any]:
        """加载并验证 YAML 配置文件"""
        # 添加对 config_path 为 None 的检查
        if self.config_path is None:
            raise ValueError("配置路径为 None，无法加载配置文件")

        if not self.config_path.exists():
            raise FileNotFoundError(f"配置文件不存在: {self.config_path}")

        try:
            with open(self.config_path, 'r', encoding='utf-8') as f:
                config = yaml.safe_load(f)
                return config if isinstance(config, dict) else {}  # 确保返回字典
        except yaml.YAMLError as e:
            raise ValueError(f"YAML 解析错误: {e}")
        except Exception as e:
            raise RuntimeError(f"读取配置文件失败: {e}")

    def get(self, key_path: str, default: Any = None) -> Any:
        """
        获取配置值（自动处理字典嵌套和列表索引）
        类型需自行判断 isinstance(value, dict/list)

        示例:
            config.get('server.ports.0')  # 获取列表中的第一个端口
            config.get('database.credentials.username', default='admin')
        """
        keys = key_path.split('.')
        value = self.config

        for key in keys:
            try:
                # 处理数字索引（如 'database.ports.0'）
                if isinstance(value, list) and key.isdigit():
                    key = int(key)
                value = value[key]
            except (KeyError, IndexError, TypeError, AttributeError):
                return default

        # 返回子配置文件或原始值
        return ConfigManager(config_data=value) if isinstance(value, dict) else value

    def __str__(self) -> str:
        """格式化输出配置内容"""
        return yaml.dump(self.config, default_flow_style=False, sort_keys=False)


config = ConfigManager()

# 使用示例
if __name__ == "__main__":
    # 示例配置结构
    _EXAMPLE_CONFIG = """
    server:
      host: "0.0.0.0"
      ports: [8000, 8001]
      debug: true
    database:
      mysql:
        port: 3307
        rootPwd: "nrlj2023"
        database:
          - dbname: "nrljdevdb"
            user: "ljdevuser"
            pwd: "lianji$2023"
          - dbname: "ljrhdb"
            user: "rhzc"
            pwd: "rhzc$2023"
    """

    # 1. 绕过默认配置文件，从字符串加载，方便测试
    print(
        "yaml中非端点的内容，大部分是字典，少部分是列表。"
        "本class实现代码，统一用get获取端点内容;"
        "统一用get获取大部分 非端点内容；"
        "针对列表内容，用 p[i] 访问，或者遍历访问")
    config = ConfigManager(config_data=yaml.safe_load(_EXAMPLE_CONFIG))

    # 2. 读取样例
    print("直接访问端点元素 server.ports.0 :", config.get('server.ports.0'))
    print("直接访问端点元素 database.mysql.database.1.user :", config.get('database.mysql.database.1.user'), '\n')

    mysql = config.get('database.mysql')
    print("非端点内容 database.mysql :\n", mysql)
    print("访问非端点内容 .port ", mysql.get('port'))

    print("返回列表:", config.get('server.ports'))
    p = config.get('server.ports')
    print(f"访问列表 p[0] :{p[0]}\n")
    for p in config.get('server.ports'):
        print(f"遍历列表：{p}")
    mysqldb = config.get('database.mysql.database')
    print(f"\n列表元素 是2个字典 {mysqldb} 遍历")
    for db in mysqldb:
        print(f"dbname {db.get('dbname')}")
        print(f"user {db.get('user')}")
        print(f"pwd {db.get('pwd')}\n")
